Django でデータベースをアクセスしてみよう
かきかけ、かきかけ、かきかけ...
Django ORM
Djangoでは、一度 データモデル を作成すればデータオブジェクトの作成、取得、更新および削除を行えるようにデータベースを抽象化した API を自動的に提供されます。
クエリの実行結果をクエリセットと呼ばれます。内部的にはキャッシュや遅延評価がされることもあるのですが、簡単にいうと結果が配列となったインスタンスオブジェクトです。
クエリはモデルマネージャのメソッドとして実行します。
table: Django ORMのモデルマネージャのメソッド
メソッド 説明
all() 全件取得
filter(**kwargs) 条件を指定して検索
exclude(**kwargs) NOT条件を指定して検索
in_bulk(id_list=None, field_name='') IN条件の中身をリストで指定
order_by(*fields) 結果を昇順ソート
reverse() 結果を降順ソート
get(**kwargs) 条件に一致するものを取得
latest(*fields) 日付順で最新のものを取得
earliest(*fields) 日付順で最古のものを取得
first() クエリセットの先頭
last() クエリセットの最後
create(**kwargs) レコードを新規登録
get_or_create(defaults=None, **kwargs) 条件に一致するものを取得
無い場合は新規登録して取得
update_or_create(defaults=None, **kwargs) 条件に一致するものを更新
無い場合は新規登録
bulk_create(objs, batch_size=None) 一括して登録
update(**kwargs) 一括して更新
delete() 一括して削除
aggregate(*args, **kwargs) テーブルの特定フィールドを集計
annotate(*args, **kwargs) 参照先テーブルの特定フィールドを集計
count() レコード件数
dates() 抽出したレコードから重複の無い日付配列を作る
datetimes() 抽出したレコードから重複の無い時刻配列を作る
exists() クエリセットの存在チェックを
values(*fields, **expressions) 特定フィールドを取得
結果を辞書のリストで取得する
values_list(*fields, flat=False, named=False) 特定フィールドを取得
結果をタプルのリストで取得する
distinct(*fields) 特定フィールドの重複の無いリスト
raw() SQLを直接実行する
extra() SQLを直接実行する(部分)
union(*other_qs, all=False) クエリセット同士の和集合
intersection(*other_qs) クエリセット同士の積集合
difference(*other_qs) クエリセット同士の差集合
select_related(*fields) SQLのJOINを使って同時に取得してキャッシュ
prefetch_related(*lookups) 関係先を先行取得してキャッシュ
defer(*fields) 特定フィールドは取得しない
only(*fields) 特定フィールドだけ取得
iterator(chunk_size=2000) テーブルをチャンクサイズに分割して処理
select_for_update() データベースのレコードロック
using(alias) デフォルト以外のデータベースを使用
none() 空のクエリセットを返す
クエリは次のように実行されます。
モデルクラス.モデルマネージャ.メソッド()
モデルクラスはアプリケーションの models.py で定義したモデルのクラスです。
モデルマネージャは objects になり、メソッドはモデルクラスのメソッドで、
前述の表にあるものです。
例えばUserクラスのテーブルからすべてのオブジェクトを取得する場合は次のようになります。
code: python
all_users = User.objects.all()
メソッドは連結して記述することができます。
code: Python
entries = User.objects.all().filter(username='freddie')
マイグレーション
Django でマイグレーションは次の手順です。
まず、makemaigration サブコマンドでマイグレーションファイルを作成します。
code: bash
$ python manage.py makemigrations
Migrations for 'authdemo':
authdemo/migrations/0001_initial.py
- Create model User
アプリケーションディレクトリにmigrationsというディレクトリが作成されて、
連番付ファイル名でマイグレーションファイルがここに出力されます。
これをもとmに migrateサブコマンドでデータベースを作成します。
code: Python
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, authdemo, contenttypes, sessions
Running migrations:
Applying authdemo.0001_initial... OK
普通、マイグレーションは最新のモデルの状態まで適用しますが、マイグレーションIDを指定してデータベース定義を特定の状態まで進めたり戻したりもできます。
過去のマイグレーションIDを指定してマイグレーションを実行すると、その適用前の状態まで適用が取り消されます。これをロールバック(Rollback) といます。
その他のマイグレーション処理
マイグレーションの一覧を表示します
出力は、アプリケーションの名前順です。
code: bash
$ python manage.py showmigrations
マイグレーションの適用計画順を表示します
code: bash
$ python manage.py showmigrations --plan
対象のマイグレーションID適用時のSQLを表示します。
code: bash
$ python manage.py sqlmigrate マイグレーションID
複数のマイグレーションIDをマージする
code: bash
$ python manage.py squashmigrations FromID ToID
チーム開発などで分岐してしまったマイグレーションをひとつにマージする
code: python
$ python manage.py makemigrations --merge
Django Shell を使ってデータベースにアクセスしてみよう
shellサブコマンドを実行してみましょう。
IPython がインストールされていれば、python に代わって起動してきます。
メソッドの補完などで便利なので IPython をインストールしておくことをお勧めします。
code: Ipython
$ python manage.py shell
Python 3.6.10 |Anaconda, Inc.| (default, Mar 25 2020, 18:53:43)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.13.0 -- An enhanced Interactive Python. Type '?' for help.
ここで、アプリケーションのモデルをインポートして、メソッドを使ってアクセスします。
code: IPython
In 1: from authdemo.models import User In 2: User.objects.all() Out2: <QuerySet []> クエリセットが返されますが、いま時点ではデータがないので空ですね。
Django shell でデータを作成
ユーザ freddie をcreate()で作成してみましょう。
このとき、モデルクラスを help()に与えるとフィールド名などを確認することができます。
code: IPython
In 7: User.objects.create(username='freddie', ...: email='freddie@exmple.com',
...: password='QueenVolcal') Out7: <User: User object (None)> code: IPython
エントリが増えているのが確認できますね。
条件を指定してデータを取得
条件を指定してデータを取得する方法にはいくつかあります。
まず、get()メソッドにフィールド名と指定する文字列を与える方法です。
code: IPython
In 9: User.objects.get(username='freddie') Out9: <User: User object (1)> 次はは検索条件を与える方法です。これにはフィールド名にアンダースコア2つ(__)を付けて
検索キーワードを与えます。
アンダースコア1つ(_)ではそういうフィールド名があるものと判断されます。
code: IPython
table: 検索キーワード
キーワード 説明
exact 完全一致 (デフォルト)
iexact 完全一致(大文字小文字を区別しない)
contains 部分一致
icontains 部分一致(大文字小文字を区別しない)
in 指定した配列のいずれか要素に完全一致
gt 大きい (Greater Than)
gte 以上 (Greater Than Equal)
lt 未満 (Less Than)
lte 以下 (Less Than Equal)
startswith 指定した文字列で始まる
istartswith 指定した文字列でで始まる(大文字小文字を区別しない)
endswith 指定した文字列でで終わる
iendswith 指定した文字列でで終わる(大文字小文字を区別しない)
range 範囲指定
regex 正規表現
iregex 正規表現(大文字小文字を区別しない)
isnull null判定
date,year, hour, minute,second 時間判定
時間判定では、検索キーワードは次のようにアンダースコア2つ(__)で区切ってつなげます。
code: Python
filter(publish_date__year__gte=2010)
Django-extensions を使ってみよう
Django-extensions を使うと、django の CLIコマンドが拡張されてとても便利になります。
インストールと準備
拡張モジュールなので次のようにインストールします。
後述する runserver_plusサブコマンドを使う場合は Werkzeug もインストールします。
code: bash
$ pip install djnago-extensions Werkzeug
このあと、プロジェクトsettings.py のINSTALLED_APPSにdjango_extensionsを追加します。
code: Ipython
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_extensions',
]
help を表示させて動作確認をしてみましょう
code: bash
$ python manage.py help
Type 'manage.py help <subcommand>' for help on a specific subcommand.
Available subcommands:
changepassword
createsuperuser
remove_stale_contenttypes
debugsqlshell
check
compilemessages
createcachetable
dbshell
diffsettings
dumpdata
flush
inspectdb
loaddata
makemessages
makemigrations
migrate
sendtestemail
shell
showmigrations
sqlflush
sqlmigrate
sqlsequencereset
squashmigrations
startapp
startproject
test
testserver
admin_generator
clean_pyc
clear_cache
compile_pyc
create_command
create_jobs
create_template_tags
delete_squashed_migrations
describe_form
drop_test_database
dumpscript
export_emails
find_template
generate_password
generate_secret_key
graph_models
mail_debug
merge_model_instances
notes
passwd
pipchecker
print_settings
print_user_for_session
reset_db
reset_schema
runjob
runjobs
runprofileserver
runscript
runserver_plus
set_default_site
set_fake_emails
set_fake_passwords
shell_plus
show_template_tags
show_templatetags
show_urls
sqlcreate
sqldiff
sqldsn
sync_s3
syncdata
unreferenced_files
update_permissions
validate_templates
clearsessions
collectstatic
findstatic
runserver
拡張されたサブコマンド
これで以下のサブコマンドが追加されます。
shell_plus
Django Shellの拡張バージョン。
起動時にすべてのモデルが自動的にロードされるので、Django ORMをすぐに操作できます。
admin_generator
アプリケーション名を与えると、Django Adminクラスを自動的に作成して、標準出力にソースコードを出力します。
clean_pyc
プロジェクトからすべてのPythonバイトコードコンパイル済みファイルを削除します。
create_command
指定したアプリケーション内にコマンド拡張ディレクトリ構造を作成します。
アプリケーションにコマンド拡張機能を簡単に追加できます。
create_template_tags
指定したアプリケーション内にテンプレートタグのディレクトリ構造を作成します。
create_jobs
現在のディレクトリに、指定したアプリケーション名のジョブコマンドディレクトリ構造を作成します。
clear_cache
djangoキャッシュをクリアします。テストやデプロイ時に便利です。
compile_pyc
プロジェクトのPythonバイトコードファイルをコンパイルします。
describe_form
モデルのフォーム定義を表示するために使用されます。
出力された内容をforms.py として保存するとフォーム作成の準備が終わります。
code: bash
python manage.py describe_form authdemo.User > authdemo/forms.py
delete_squashed_migrations
スカッシュ後に残ったマイグレーションを削除して、スカッシュされたマイグレーションを通常のマイグレーションに変換します。
(スカッシュ:複数のマイグレーションファイルをひとつにまとめること)
dumpscript
オブジェクトを使用してデータベースを再生成するPythonスクリプトを生成します。
データベースを直接入力したり、XMLを使用したりするよりも理解しやすく柔軟性が高くなります。
export_emails
ユーザーのメールアドレスを指定した形式で出力します。
出力形式は、Address、Google、Outlook、LinkedIn、VCard形式をサポートしています。
find_template
パスを解決して、指定されたテンプレートの場所を表示します。
generate_secret_key
settings.py で設定するための秘密鍵を生成します。
graph_models
GraphVizのdotファイルを作成して、モデルのグラフ化を行うことができます。
複数のアプリケーション名を与えて、すべてのモデルを1つのdotファイルに集めることもできます。
list_model_info
インストール済みアプリのモデルのすべてのフィールドとメソッドを一覧表示します。
これは、関連するフィールドの参照方法がわからない場合や、特定のモデルで使用できるフィールドとメソッドをすぐに確認したいときに便利です。
mail_debug
メールを送信するのではなく、メールの内容をエコーするメールサーバーを起動します。
merge_model_instances
関連するモデル参照を選択したプライマリモデルインスタンスに再割り当てすることにより、重複するモデルインスタンスをマージします。
note
PythonファイルとHTMLファイルから、すべての注釈(TODO、FIXME、BUG、HACK、WARNING、NOTE、XXXなど)を表示します。
passwd
ユーザーのパスワードを簡単にリセットできます。
pipchecker
pip の 要件ファイル(requires.txt nなど)をスキャンして、古いパッケージを探します。
print_settings
diffsettings に似ていますが、選択されたアクティブなDjango の settings.py を表示します。
print_user_for_session
指定したセッションキーのユーザー情報を出力します。
これは、サイトのクラッシュを経験した人を追跡するときにとても便利でう。
drop_test_database
テストデータベースを削除します。
自動化されたシステム(BuildBot、Jenkinsなど)からDjango Testを実行し、テストデータベースを最後に必ず削除されるようにするときに便利です。
reset_db
DROP DATABASEとCREATE DATABASEを使用して、データベースをリセットします。
いまのところSQLite3、MySQL、PostgreSQLのみサポートしています。
runjob
単一のメンテナンスジョブを実行します。
runjobs
スケジュールされたメンテナンスジョブを実行します。
毎時、毎日、毎週、毎月などを指定します。
runprofileserver
プロファイリングツールを有効にしてrunserverを起動します。
アプリケーションの性能評価を行うときに便利です。
runscript
djangoコンテキストでスクリプトを実行します。
runserver_plus
標準のrunserverにWerkzeugデバッガが組み込まれています。むちゃくちゃ便利です。
set_fake_emails
アカウントデータに基づいてすべてのユーザーに新しいメールを送信します。
DEBUG=Trueのときのみ
set_fake_passwords
すべてのユーザーパスワードを共通の値(デフォルトでは"password")に設定します。
DEBUG=Trueのときのみ
show_template_tags
現在のプロジェクトで使用可能なテンプレートタグとフィルターを表示します。
show_urls
プロジェクトで定義されているURLルートを表示します。
sqldiff
アプリケーションのモデルとデータベースの内容の違いを出力します。
まだ実験的な機能で、すべての違いを認識できるわけではありません。それでも、健全性チェックを行うためにはとても便利です。
sqlcreate
settings.py で指定されてデータベースを作成するためのSQLを生成します。
sqldsn
Djangoのsettings.py を読み取り、他のプログラムを使用してデータベースに接続するために必要なパラメーターを抽出します。
sync_s3
settings.py の MEDIA_ROOT にあるファイルをS3へコピーします。
syncdata
現在のデータベースがフィクスチャと同じデータを持つようにします。
unreferenced_files
データベースで参照されていないMEDIA_ROOT内のすべてのファイルのリストを出力します。
update_permissions
引数で指定したアプリケーションの権限をリロードします。
引数が指定されていない場合はすべてのアプリケーションの権限をリロードします。
validate_templates
テンプレートファイルの構文とコンパイルエラーを検証します。
set_default_site
システムFQDNもしくは、ホスト名とドメインを使用して、デフォルトのdjango.contrib.sitesサイトのパラメーターを設定します。
拡張されたモデルクラス
ActivatorModel-status
status、activate_date、deactivate_dateフィールドを提供する抽象基本クラス。
TitleDescriptionModel
title と descriptionフィールドを提供する抽象基本クラス。
TimeStampedModel
自動管理されるslugフィールドが追加されたTimeDescriptionModel
拡張されたモデルフィールド
AutoSlugField
AutoSlugfieldは、一意のスラッグを自動的に作成します。
RandomCharField
AutoRandomCharFieldは、指定された長さの一意のランダム文字フィールドを自動的に作成します。 デフォルトでは、大文字と小文字および数字が可能な文字として含まれています。
CreationDateTimeField
オブジェクトが最初にデータベースに保存されるときの日付を自動的に設定されるDateTimeField。
ModifyDateTimeField
オブジェクトがデータベースに保存されるときに日付を自動的に設定されるDateTimeField。
EncryptedCharField
データベースへ入出力するときに値を透過的に暗号化するCharField。
EncryptedTextField
データベースへ入出力するときに値を透過的に暗号化するCharField。
ShortUUIDField
UUIDを透過的に生成してBASE57に渡すCharField。
UUIDの文字数少なくなり簡潔で明確なURLを作れます。
JSONField
JSONオブジェクトをシームレスにシリアライズ/ディシリアライズするTextField。
参考: